Skip to content

Conversation

nicolas-guichard
Copy link

As the docs currently state about shared enums:

Pattern matching with match still works but will require you to write wildcard arms to handle the situation of an enum value that is not one of the listed variants.

This is unfortunate as there is no way to check that all listed enum variants are actually handled. IOW this code does not even warn:

mod ffi {
    enum Enum {
        A,
        B,
        C = 5,
    }
}

match t {
    Enum::A => {},
    Enum::B => {},
    _ => {},
}

This generates an extra _Enum! macro that matches all the ranges that are not listed by the enum. When using that macro instead of the _ catch-all, we get compile-time errors if we forget to match variants:

match t {
    Enum::A => {},
    Enum::B => {},
    _Enum!() => {},
}
// Error Enum{ repr: 5 } case not covered

The generated macro looks like:

macro_rules! _Enum {
    () => { Enum{ repr: 4..5 | 6.. } };
    ($i:ident) => { Enum { repr: $i @ 4..5 | 6.. } };
}

It can also be used to ergonomically retrieve the inner value in the unlisted case:

match t {
    Enum::A => {},
    Enum::B => {},
    Enum::C => {},
    _Enum!(value) => panic!("Unexpected Enum value {value}"),
}

I would have preferred something like Enum::unlisted!, but macro definitions are not supported in impls. I think _Enum carries the meaning of _ specific to Enum, but I'm open to other naming/namespacing ideas.

As the docs currently state about shared enums:
> Pattern matching with match still works but will require you to write
> wildcard arms to handle the situation of an enum value that is not
> one of the listed variants.

This is unfortunate as there is no way to check that all listed enum
variants are actually handled. IOW this code does not even warn:
```
mod ffi {
    enum Enum {
        A,
        B,
        C = 5,
    }
}

match t {
    Enum::A => {},
    Enum::B => {},
    _ => {},
}
```

This generates an extra _Enum! macro that matches all the ranges that
are _not_ listed by the enum. When using that macro instead of the _
catch-all, we get compile-time errors if we forget to match variants:
```
match t {
    Enum::A => {},
    Enum::B => {},
    _Enum!() => {},
}
// Error Enum{ repr: 5 } case not covered
```

The generated macro looks like:
```
macro_rules! _Enum {
    () => { Enum{ repr: 4..5 | 6.. } };
    ($i:ident) => { Enum { repr: $i @ 4..5 | 6.. } };
}
```

It can also be used to ergonomically retrieve the inner value in the
unlisted case:
```
match t {
    Enum::A => {},
    Enum::B => {},
    Enum::C => {},
    _Enum!(value) => panic!("Unexpected Enum value {value}"),
}
```
Limits::of(atom).expect("Unexpected EnumRepr")
}
#[cfg(feature = "experimental-enum-variants-from-header")]
&EnumRepr::Foreign { rust_type: _ } => todo!(),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NB: this TODO should obviously be fixed before this can be merged.

Copy link
Owner

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! This is a neat idea but I would prefer not to provide this in this library.

I would suggest making a separate proc macro that users could put on an ffi module to generate these macros for its enums.

@dtolnay dtolnay closed this Aug 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants